﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;



using DotSpatial.Data;

using DotSpatial.Topology;

using Point = System.Drawing.Point;



namespace FXnaGis
{


    /// <summary>
    /// 要求同时支持 框选 以及 点选
    /// </summary>
    public  class FSelectMF:FMapFunction
    {

        public FSelectMF(FMapFrame frame)
            : base(frame)
        {

            this._enabled = false;


            //默认的选择用框笔

            _selectionPen = new Pen(Color.Black) { DashStyle = DashStyle.Dash };

            frame.LayerService.SelectionChanged += new EventHandler(LayerService_SelectionChanged);

            frame.BufferChanged += new EventHandler<FClipArgs>(frame_BufferChanged);



            //右键系统,配置常用的选项


            this._contextMenuStrip = new ContextMenuStrip();




        }

        void frame_BufferChanged(object sender, FClipArgs e)
        {
            this.OnSelectionChanged();
        }




        private bool _isDragging;
        private Point _startPoint;
        private Coordinate _geoStartPoint;
        private Point _currentPoint;




        private readonly Pen _selectionPen;


        FSelectionMode currentSelectionMode = FSelectionMode.InterSection;

        /// <summary>
        /// 对外的选择模式接口
        /// </summary>
        public FSelectionMode CurrentSelectionMode
        {
            get { return currentSelectionMode; }
            set { currentSelectionMode = value; }
        }



        protected List<Extent> _selectedExtents = new List<Extent>();



        protected ContextMenuStrip _contextMenuStrip;

        /// <summary>
        /// 对外的右键菜单系统
        /// </summary>
        public ContextMenuStrip ContextMenuStrip
        {
            get { return _contextMenuStrip; }
            set { _contextMenuStrip = value; }
        }

       
       



        protected virtual void OnSelectionChanged()
        {
            //这里还需要考虑深层嵌套问题，fgrouplayer,目前还不知道怎么办好


            this._selectedExtents.Clear();

            List<FVectorLayer> layers = this._geoMapFrame.LayerService.GetVectorLayers();

            foreach (FVectorLayer layer in layers)
            {

              
                    foreach (FShape shape in layer.SelectedShapes)
                    {

                        Extent ext = shape.Extent;

                        if (null != ext)
                        {



                            this._selectedExtents.Add(ext);

                        }

                    }

                



            }
 
        }

        void LayerService_SelectionChanged(object sender, EventArgs e)
        {

            this.OnSelectionChanged();


           
        }





        /// <summary>
        /// 被选中状态下的物体绘制
        /// </summary>
        /// <param name="e"></param>
        protected override void OnDraw(FMapDrawArgs e)
        {



            this.DrawSelectedRect(e.Graphics);

         
         




            if (_isDragging)
            {
                // don't draw anything unless we need to draw a select rectangle
                Rectangle r = ShapeHelper.RectangleFromPoints(_startPoint, _currentPoint);
                r.Width -= 1;
                r.Height -= 1;
                e.Graphics.DrawRectangle(Pens.White, r);
                e.Graphics.DrawRectangle(_selectionPen, r);
            }


            base.OnDraw(e);






        }

        protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
        {
            base.OnMouseDown(e);

            if (e.Button == MouseButtons.Left)
            {
                _startPoint = e.Location;

               this._geoStartPoint=  this._geoMapFrame.BufferToProj(e.Location);

                //_geoStartPoint = e.GeographicLocation;

                _isDragging = true;
                
            }

            if (e.Button==MouseButtons.Right)
            {
                this.ContextMenuStrip.Show(this._geoMapFrame.Parent,e.Location);
                
            }




        }


        protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e)
        {
            base.OnMouseMove(e);


          
            if (_isDragging)
            {
                  int x = Math.Min(Math.Min(_startPoint.X, _currentPoint.X), e.X);
                    int y = Math.Min(Math.Min(_startPoint.Y, _currentPoint.Y), e.Y);
                    int mx = Math.Max(Math.Max(_startPoint.X, _currentPoint.X), e.X);
                    int my = Math.Max(Math.Max(_startPoint.Y, _currentPoint.Y), e.Y);
                    _currentPoint = e.Location;


                this._geoMapFrame.Parent.Invalidate(new Rectangle(x, y, mx - x, my - y));
            }



        }



        protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
        {
            base.OnMouseUp(e);

            if (_isDragging == false) return;

            if (e.Button == MouseButtons.Left)
            {

                _currentPoint = e.Location;
                _isDragging = false;

                Coordinate endCoord=this._geoMapFrame.BufferToProj(e.Location);


                IEnvelope env = new Envelope(_geoStartPoint.X, endCoord.X,
               _geoStartPoint.Y, endCoord.Y);

                IEnvelope tolerant = env;



                if (_startPoint.X == e.X && _startPoint.Y == e.Y)
                {
                    //这里我们认为触发了点选模式，也即是坐标相同，我们这里做一个适当的放大

                    //原始的代码是根据地理坐标的本分比做的查询，感觉如果是普通绘图的话，是不是以pixel计算好一点，当然这在变化比例较大时，会产生比较大的误差，
                    //貌似这里是基于视图的，所以我觉得可行

                    //我们假设外扩2个像素
                    double tol = this._geoMapFrame.BufferToProj(2);


                    //同时，我们这里发现了一个非常严重的选择系统的问题，选择不能基于extent，因为它是方形的，需要些独立的碰撞算法，之前失误了

                    // click selection doesn't work quite right without some tiny tolerance.
                    //tol = this._geoMapFrame.ViewExtents.Width / 10000;


                    env.ExpandBy(tol);

                }

                if (Math.Abs(_startPoint.X - e.X) < 8 && Math.Abs(_startPoint.Y - e.Y) < 8)
                {
                    Coordinate c1 = this._geoMapFrame.BufferToProj(new Point(e.X - 4, e.Y - 4));
                    Coordinate c2 = this._geoMapFrame.BufferToProj(new Point(e.X + 4, e.Y + 4));
                    tolerant = new Envelope(c1, c2);
                }

                this._geoMapFrame.SuspendEvents();
                HandleSelection(tolerant, env);
                this._geoMapFrame.ResumeEvents();



                // Force an invalidate to clear the dotted lines, even if we haven't changed anything.
                //去掉选择的点框
                this._geoMapFrame.Parent.Invalidate();




            }
        }

          
        private void HandleSelection(IEnvelope tolerant, IEnvelope strict)
        {

                  //这里我们规定，ALT是减少 shift是增减

            Keys key = Control.ModifierKeys;
            if ((((key & Keys.Shift) == Keys.Shift) == false)
                && (((key & Keys.Alt) == Keys.Alt) == false))
            {




                this._geoMapFrame.Select(strict.ToExtent(),this.currentSelectionMode,FSelectionOperationMode.Normal);



             

            }

            if ((key & Keys.Shift) == Keys.Shift && (((key & Keys.Alt) == Keys.Alt) == false))
            {

                //增加选择模式

                this._geoMapFrame.Select(strict.ToExtent(), this.currentSelectionMode, FSelectionOperationMode.Additive);

               
            }

            if ((((key & Keys.Shift) == Keys.Shift) == false)
                && (((key & Keys.Alt) == Keys.Alt) == true))
            {
                

                //减少选择模式

                this._geoMapFrame.Select(strict.ToExtent(), this.currentSelectionMode, FSelectionOperationMode.Exclude);



            }


            


    






        }


        protected void DrawSelectedRect(Graphics g)
        {

            //这里我们想尝试建立类似于3dsmax的选择绘图机制

            Pen pen = new Pen(Color.Black, 2);



            foreach (Extent ext in this._selectedExtents)
            {

                Rectangle rect = this._geoMapFrame.ProjToBuffer(ext);

                //这里我们默认先使用红色，且外扩两个像素

                rect = rect.ExpandBy(2);

                //绘制包围矩形，要求中空，边线也中空，看下效果,先等等吧，以后又事件在慢慢的绘制

                //e.Graphics.DrawLine(pen,rect.Left,rect.Bottom);


                //g.DrawRectangle(pen, rect);


                GDIHelper.DrawBoundingBox(g,pen,rect);

            }


            pen.Dispose();
 
        }



    }



}
